#include "ST75320.H"

#include "stm32f1xx_hal.h"

extern const unsigned char gImage_320240_1[9600];
extern const unsigned char gImage_320240_2[9600];
extern const unsigned char gImage_320240_3[9600];
extern const unsigned char gImage_frame_triangle[9600] ;

extern const unsigned char gImage_testimg1[9600];
extern const unsigned char gImage_testimg2[9600];
extern const unsigned char gImage_testimg3[9600];

extern const unsigned char gImage_frame_triangle_160240[9600];

extern const unsigned char gImage_Device_settings[4800];
extern const unsigned char gImage_Function[4800];
extern const unsigned char gImage_Information[4800];
extern const unsigned char gImage_Receiver_settings[4800];

#define SEQ_MAX 17
uint8_t seqIndex = 0;
uint8_t isDrawing = 0;
uint8_t ispause = 0;

void _nop_(void) {

}

unsigned char i;
void write_com(unsigned char byte)
{
	LCM_A0_GPIO_Port->BRR = (uint32_t) LCM_A0_Pin;
	LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
	LCM_CS_GPIO_Port->BRR = (uint32_t) LCM_CS_Pin;
	
	for(i=0;i<8;i++)
	{
		LCM_SCK_GPIO_Port->BRR = (uint32_t) LCM_SCK_Pin;
		(byte&0x80) ? (LCM_MOSI_GPIO_Port->BSRR = (uint32_t) LCM_MOSI_Pin) : (LCM_MOSI_GPIO_Port->BRR = (uint32_t) LCM_MOSI_Pin);
		byte <<= 1;
		LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
	}
	LCM_CS_GPIO_Port->BSRR = (uint32_t) LCM_CS_Pin;
}

void write_data(unsigned char byte)
{
	LCM_A0_GPIO_Port->BSRR = (uint32_t) LCM_A0_Pin;
	LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
	LCM_CS_GPIO_Port->BRR = (uint32_t) LCM_CS_Pin;
	
	for(i=0;i<8;i++)
	{
		LCM_SCK_GPIO_Port->BRR = (uint32_t) LCM_SCK_Pin;
		(byte&0x80) ? (LCM_MOSI_GPIO_Port->BSRR = (uint32_t) LCM_MOSI_Pin) : (LCM_MOSI_GPIO_Port->BRR = (uint32_t) LCM_MOSI_Pin);
		byte <<= 1;
		LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
	}
	LCM_CS_GPIO_Port->BSRR = (uint32_t) LCM_CS_Pin;
}

void write_multi_data(unsigned char *bytes, uint32_t length) {
	/*LCM_A0_GPIO_Port->BSRR = (uint32_t) LCM_A0_Pin;
	
	uint32_t i = length;
	do{
		LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
		LCM_CS_GPIO_Port->BRR = (uint32_t) LCM_CS_Pin;
		for(uint8_t j=0;j<8;j++) {
			LCM_SCK_GPIO_Port->BRR = (uint32_t) LCM_SCK_Pin;
			(bytes[i]&0x80) ? (LCM_MOSI_GPIO_Port->BSRR = (uint32_t) LCM_MOSI_Pin) : (LCM_MOSI_GPIO_Port->BRR = (uint32_t) LCM_MOSI_Pin);
			bytes[i] <<= 1;
			LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
		}
		LCM_CS_GPIO_Port->BSRR = (uint32_t) LCM_CS_Pin;
	} while(i--);*/
	
	for(uint32_t i = 0 ; i < length; i++) {
		LCM_A0_GPIO_Port->BSRR = (uint32_t) LCM_A0_Pin;
		LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
		LCM_CS_GPIO_Port->BRR = (uint32_t) LCM_CS_Pin;
		uint8_t byte = bytes[i];

		for(i=0;i<8;i++)
		{
			LCM_SCK_GPIO_Port->BRR = (uint32_t) LCM_SCK_Pin;
			(byte&0x80) ? (LCM_MOSI_GPIO_Port->BSRR = (uint32_t) LCM_MOSI_Pin) : (LCM_MOSI_GPIO_Port->BRR = (uint32_t) LCM_MOSI_Pin);
			byte <<= 1;
			LCM_SCK_GPIO_Port->BSRR = (uint32_t) LCM_SCK_Pin;
		}
		LCM_CS_GPIO_Port->BSRR = (uint32_t) LCM_CS_Pin;
	}
}


void delay_ms(uint8_t time) {
	HAL_Delay(time);
}

void lcm_init(void) {
	HAL_GPIO_WritePin(LCM_SCK_GPIO_Port, LCM_SCK_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(LCM_MOSI_GPIO_Port, LCM_MOSI_Pin, GPIO_PIN_SET);

    HAL_GPIO_WritePin(LCM_RST_GPIO_Port, LCM_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(10);
    HAL_GPIO_WritePin(LCM_RST_GPIO_Port, LCM_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(100);
    HAL_GPIO_WritePin(LCM_RST_GPIO_Port, LCM_RST_Pin, GPIO_PIN_SET);


    write_com(0xff);     //auto read disable
	write_com(0x96);
	write_data(0x30); 
	write_com(0x94);     //Download from OTP
delay_ms(50);   
				 
	write_com(0xFE);    //CMD MODE
	write_com(0xB0);    //Display Setting 
	write_data(0x03);     
	write_com(0xB3);  //Display Setting 
	write_data(0x04); 
		  
			  
	write_com(0xFC);    //CMD MODE
	write_com(0xAB);    //OSC ON
	write_com(0x69);    //Temperature Detection ON
	write_com(0x4E);    //TC Setting
	write_data(0x00);       // 0mv/'C should be adjusted by user
	write_data(0x00);       // 0mv/'C should be adjusted by user
	write_data(0x00);       // 0mv/'C should be adjusted by user 
	write_data(0x00);       // 0mv/'C should be adjusted by user 
	write_data(0x00);       // 0mv/'C should be adjusted by user 
	write_data(0x00);       // 0mv/'C should be adjusted by user 
	write_data(0x00);       // 0mv/'C should be adjusted by user 
	write_data(0x00);       // 0mv/'C should be adjusted by user 
	write_com(0x39);    //TC Flag
	write_data(0x00);       // 
	write_data(0x00);       //
	write_com(0x2b);    //Double FR
	write_data(0x00);       //x1
	write_com(0x66);    //Mono
	write_data(0x00);       //
	write_com(0x5f);    //Set Frame Rate
	write_data(0x33);       //80Hz
	write_data(0x33);       //

	write_com(0xEC);    //FR Compensation Temp. Range
	write_data(0x14);       // -20'c 
	write_data(0x41);       //  25'c
	write_data(0x6e);       // 70'c
	write_com(0xC4);    //COM Output Status
	write_data(0x02);       // 
	write_com(0xA0);    //MX
	write_com(0xA8);    //Sleep-Out                                                                                            
	write_com(0xA2);    //1/16bias  
	write_data(0x07);      
	
	write_com(0x25);
	write_data(0x20);
delay_ms(0x50);
	write_com(0x25);
	write_data(0x60);
delay_ms(0x50);
	write_com(0x25);
	write_data(0x72);
delay_ms(0x50);
	write_com(0x25);
	write_data(0x76);
//delay_ms(0x100); 
	delay_ms(0x50);
	delay_ms(0x50);	
	
	write_com(0x25);
	write_data(0x6f);
//delay_ms(0x500);
	delay_ms(0x50);
	delay_ms(0x50);	
	delay_ms(0x50);
	delay_ms(0x50);	
	delay_ms(0x50);
	
	write_com(0x25);
	write_data(0x7f);
//delay_ms(0x100);   
	delay_ms(0x50);
	delay_ms(0x50);
	
	
	write_com(0x81);    //Vop=24.4V                  
	//write_data(0x68);
	//write_data(0x01);  
	write_data(0x13);
	write_data(0x01);
	write_com(0xAF);    //Display ON

}

void display_setting(void) {
	write_com(0xc4);			//COM Output Status
	write_data(0x02);
	
	write_com(0x8a);			//Display Start Line
	write_data(0);
	
	write_com(0x84);			//Display Data Input/Output Direction
	
	write_com(0xa0);			//Column Address Direction
	
	write_com(0x6d);			//Display Area
	write_data(0x07);
	write_data(0x00);
}

void chess(void) {
	unsigned long c, p = 0;
	write_com(0xb1);			//Page Address
	write_data(0x00);
	
	write_com(0x13);			//Column Address
	write_data(0x00);
	write_data(0x00);
	
	write_com(0x1d);			//Display Data Write
	for(p = 0; p < 240/8; p++) {
		for(c = 0; c < 320/2; c++) {
			write_data(0x55);
			write_data(0xaa);
		}
	}
}

void st75320_fillWithByte(unsigned char byte) {
	unsigned long c, p = 0;
	write_com(0xb1);			//Page Address
	write_data(0x00);
	
	write_com(0x13);			//Column Address
	write_data(0x00);
	write_data(0x00);
	
	write_com(0x1d);			//Display Data Write
	for(p = 0; p < 240/8; p++) {
		for(c = 0; c < 320; c++) {
			write_data(byte);
		}
	}
}

void st75320_fillWith4Byte(unsigned char byte1, unsigned char byte2, unsigned char byte3, unsigned char byte4) {
	unsigned long c, p = 0;
	write_com(0xb1);			//Page Address
	write_data(0x00);
	
	write_com(0x13);			//Column Address
	write_data(0x00);
	write_data(0x00);
	
	write_com(0x1d);			//Display Data Write
	for(p = 0; p < 240/8; p++) {
		for(c = 0; c < 320/4; c++) {
			write_data(byte1);
			write_data(byte2);
			write_data(byte3);
			write_data(byte4);
		}
	}
}

void disp_full(void) {
	unsigned long c, p = 0;
	write_com(0xb1);			//Page Address
	write_data(0x00);
	
	write_com(0x13);			//Column Address
	write_data(0x00);
	write_data(0x00);
	
	write_com(0x1d);			//Display Data Write
	for(p = 0; p < 240/8; p++) {
		for(c = 0; c < 320/2; c++) {
			write_data(0x55);
			write_data(0xaa);
		}
	}
}

void drawImage(unsigned char * image) {
	unsigned long c, p = 0;
		
	
	for(p = 0; p < 240/8; p++) {
		
		write_com(0xb1);			//Page Address
		write_data(p);
	
		write_com(0x13);			//Column Address
		write_data(0x00);
		write_data(0x00);
	
		write_com(0x1d);			//Display Data Write
		for(c = 0; c < 160; c++) {
			write_data(*image++);
		}
	}
	
	//write_multi_data(image, 320*240/8);
}







//#define __TESTER__
//#define __DEMO__

void testSequences(uint8_t index) {
	switch(index) {
		case 0:
			st75320_fillWithByte(0xff);
			HAL_Delay(1500);
		break;
		
		
		#ifdef __TESTER__
		case 1:
			st75320_fillWithByte(0x11);
			HAL_Delay(300);
		break;
		
		case 2:
			st75320_fillWithByte(0x22);
			HAL_Delay(300);
		break;
		
		case 3:
			st75320_fillWithByte(0x44);
			HAL_Delay(300);
		break;
		
		case 4:
			st75320_fillWithByte(0x88);
			HAL_Delay(300);
		break;
		
		case 5:
			st75320_fillWith4Byte(0xff, 0x00, 0x00, 0x00);
			HAL_Delay(300);
		break;
		
		case 6:
			st75320_fillWith4Byte(0x00, 0xff, 0x00, 0x00);
			HAL_Delay(300);
		break;
		
		case 7:
			st75320_fillWith4Byte(0x00, 0x00, 0xff, 0x00);
			HAL_Delay(300);
		break;
			
		case 8:
			st75320_fillWith4Byte(0x00, 0x00, 0x00, 0xff);
			HAL_Delay(300);
		break;
		
		#endif //__TESTER__
		
		
		#ifdef __DEMO__
		case 9:
			drawImage((unsigned char *)gImage_testimg1);
			HAL_Delay(1500);
		break;
		
		case 10:
			drawImage((unsigned char *)gImage_testimg2);
			HAL_Delay(1500);
		break;
		#endif //__DEMO__
		
		case 11:
			drawImage((unsigned char *)gImage_testimg3);
			HAL_Delay(1500);
		break;
		
		case 12:
			#ifdef __TESTER__
			drawImage((unsigned char *)gImage_frame_triangle_160240);
			HAL_Delay(1500);
			#endif //__TESTER__
		break;
		
		#ifdef __DEMO__
		case 13:
			drawImage((unsigned char *)gImage_Device_settings);
			HAL_Delay(1500);
		break;
		
		case 14:
			drawImage((unsigned char *)gImage_Function);
			HAL_Delay(1500);
		break;
		
		case 15:
			drawImage((unsigned char *)gImage_Information);
			HAL_Delay(1500);
		break;
		
		case 16:
			drawImage((unsigned char *)gImage_Receiver_settings);
			HAL_Delay(1500);
		break;
		#endif //__DEMO__
		
		default:
		break;
	}
}




void lcm_test(void) {
	display_setting();
	
	while(1) {
	
		if(ispause ) {
			
		} else {
			testSequences(seqIndex++);
			
			if(seqIndex > SEQ_MAX) {
				seqIndex = 0;
			}
		}
	}
}

void HAL_GPIO_EXTI_Callback(uint16_t pin){
	//if(pin == KEY1_Pin) 
	switch(pin) {
		case KEY1_Pin:
			if(!isDrawing) {
				if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
					write_com(0xff);
					write_com(0xd6);
					write_com(0xfd);
				}
			}
		break;

		case KEY2_Pin:
			if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET) {
				
				if(ispause == 0) {
					ispause = 1;
				} else {
					ispause = 0;
				}
			}
		break;

		case KEY3_Pin:
			if(!isDrawing) {
				if(HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == GPIO_PIN_RESET) {
					write_com(0xff);
					write_com(0xd7);
					write_com(0xfd);
				}
			}
		break;

		default:
			
		break;
	}
}
